import React, { useCallback, useContext, useRef, useState } from 'react'
import {
  Badge,
  Drawer,
  Dropdown,
  Icon,
  Input,
  Menu,
  Popconfirm,
  Select,
  Tooltip,
  Typography,
  message,
} from 'antd'
import PropTypes from 'prop-types'
import get from 'lodash/get'
import isEqual from 'lodash/isEqual'
import classnames from 'classnames'

import { connect } from 'dva'
import Context from '../targetContext'
import { ANY_TYPE, ARRAY_TYPE, OBJECT_TYPE, SCHEMA_TYPE } from '../settings'
import { getCurrentGroup, getCurrentGroups, hasRules } from '../utils'
import ConfigPanel from '../ConfigPanel'
import styles from '../styles.less'
import InstanceList from './InstanceList'
import NodeInfo from './NodeInfo'
import { hasChildren } from '@/utils/utils'
import { default as TransformerContext } from '@/pages/Transformer/context'
import { nodeName } from '@/utils/node'

const { Option } = Select
const { Text } = Typography

const timestamp = +new Date()

// 时间戳大的 优先级高，表示是当前操作的模式（全局or本地 toggle）
function isShow(global, local) {
  const { timestamp: lt, status: ls } = local

  if (typeof get(global, 'timestamp') !== 'number')
    return ls

  const { timestamp: gt, status: gs } = global

  return gt > lt ? gs : ls
}

function getInputWidth(windowWidth) {
  return (windowWidth - 3 * 8) / 2 - 16 * 2 - 30 - 24 - 90 - 8 * 7 - 13 - 14 - 126
}

function Node({ parent, nodePath, current, offset, children, windowWidth, handleSelect, disableAddNode = false }) {
  const { state = {}, dispatch } = useContext(Context)

  const { state: Tstate = {}, dispatch: Tdispatch } = useContext(TransformerContext)

  const isRoot = nodePath === ''

  const parentNodeType = get(parent, 'nodeType')

  const isArrayItem = parentNodeType === ARRAY_TYPE

  const [width] = useState(getInputWidth(windowWidth))

  const [settingVisible, setSettingVisible] = useState(false)

  // 根节点默认展开
  const [localToggle, setLocalToggle] = useState(() => ({
    timestamp,
    status: isRoot,
  }))

  const prefix = isRoot ? '' : `${nodePath}.`

  // 适用于除`rules`外的节点普通属性，
  const changeNodeNormalAttr = useCallback(
    (value, path, attrName, parent) => {
      dispatch({
        type: 'update_node_normal_attr',
        payload: {
          value,
          path,
          attrName,
          parent,
          current,
        },
      })
    },
    [current, dispatch],
  )

  const addSibingNode = useCallback(
    (parent, current, nodePath) => {
      dispatch({
        type: 'add_sibling_node',
        payload: {
          parent,
          current,
          nodePath,
        },
      })
    },
    [dispatch],
  )

  const addChildNode = useCallback(
    (parent, current, nodePath) => {
      dispatch({
        type: 'add_child_node',
        payload: {
          parent,
          current,
          nodePath,
        },
      })
    },
    [dispatch],
  )

  const deleteCurrentNode = useCallback(
    (nodePath) => {
      dispatch({
        type: 'delete_current_node',
        payload: {
          nodePath,
        },
      })
    },
    [dispatch],
  )

  // 根节点的parent预期是undefined
  function renderPlus(parent, current, nodePath) {
    const { nodeType } = current

    const parentNodeType = get(parent, 'nodeType')

    const isRoot = parent === undefined

    const isObjectRoot = isRoot && nodeType === OBJECT_TYPE

    // ## 只添加子节点
    // 1、根节点是object
    // 2、当前是object且父节点是array
    // 3、当前是array但还没有children
    const onlyChild
      = isObjectRoot
      || (parentNodeType === ARRAY_TYPE && nodeType === OBJECT_TYPE)
      || (nodeType === ARRAY_TYPE && !hasChildren(current))

    // ## 只有兄弟节点
    // 1、父节点不是array的普通节点(指除除object、boolean和array外)
    // 2、父节点是object且自身不是object的
    const onlySibling
      = (SCHEMA_TYPE.filter(k => k !== ARRAY_TYPE).includes(parentNodeType)
        && ![OBJECT_TYPE, ARRAY_TYPE].includes(nodeType))
      || (parentNodeType === OBJECT_TYPE && nodeType !== OBJECT_TYPE)

    //
    const childAndSibling = nodeType === OBJECT_TYPE && !isRoot

    if (onlyChild) {
      return (
        <Tooltip placement="top" title="子节点">
          <Icon
            type="plus"
            className={classnames(styles.action, styles.add)}
            onClick={() => {
              addChildNode(parent, current, nodePath)

              // 保证子节点添加完可见，避免添加时父节点是`收起`状态
              if (localToggle.status === false) {
                setLocalToggle({
                  timestamp: +new Date(),
                  status: true,
                })
              }
            }}
          />
        </Tooltip>
      )
    }

    if (onlySibling) {
      return (
        <Tooltip placement="top" title="兄弟节点">
          <Icon
            type="plus"
            className={classnames(styles.action, styles.add)}
            onClick={() => addSibingNode(parent, current, nodePath)}
          />
        </Tooltip>
      )
    }

    // 父节点是array时, 子节点
    if (childAndSibling) {
      return (
        <Dropdown
          overlay={
            <Menu>
              <Menu.Item>
                <span onClick={() => addSibingNode(parent, current, nodePath)}>兄弟节点</span>
              </Menu.Item>
              <Menu.Item>
                <span
                  onClick={() => {
                    addChildNode(parent, current, nodePath)

                    // 保证子节点添加完可见，避免添加时父节点是`收起`状态
                    if (localToggle.status === false) {
                      setLocalToggle({
                        timestamp: +new Date(),
                        status: true,
                      })
                    }
                  }}
                >
                  子节点
                </span>
              </Menu.Item>
            </Menu>
          }
        >
          <Icon type="plus" className={classnames(styles.action, styles.add)} />
        </Dropdown>
      )
    }

    return null
  }

  // open是内部状态
  const show = isShow(state.globalToggle, localToggle)

  const inputRef = useRef(null)

  const sourceNodePath = get(Tstate, 'sourceNodePath')

  // 快速映射
  const dotted
    = Array.isArray(sourceNodePath)
    && nodePath !== null
    && nodePath !== undefined
    && isEqual(nodePath, get(Tstate, 'targetNodePath'))

  return (
    <span
      style={{ display: 'inline-flex', alignItems: 'center' }}
      onDoubleClick={(e) => {
        e.stopPropagation()
      }}
      onClick={e => e.stopPropagation()}
    >
      {/* 防止Drawer双击 冒泡到 <Expandable />组件 */}
      {/* 展开/收起 */}
      {/* {hasChildren(current) && (
          <i
            className={classnames(styles['wtree-switcher'])}
            onClick={() =>
              setLocalToggle({
                timestamp: +new Date(),
                status: !show,
              })
            }
          >
            {show === true ? '-' : '+'}
          </i>
        )} */}

      {/* 属性名称 */}

      <i
        className={classnames(
          'tgIcon',
          `icon-${current.nodeType}`.toLocaleLowerCase(),
          styles.icon,
          styles[`${current.nodeType}`.toLocaleLowerCase()],
        )}
      />
      <Input
        readOnly={Tstate.previewMode}
        ref={inputRef}
        onClick={(e) => {
          e.stopPropagation()
          inputRef.current.select()
        }}
        onContextMenu={e => e.preventDefault()}
        defaultValue={get(current, 'nodeName')}
        onBlur={(e) => {
          if (e.target.value === current.nodeName)
            return

          if (!e.target.value) {
            message.error('key不能为空')
          }
          else if (
            parent
            && Array.isArray(parent.children)
            && parent.children.some(k => k.nodeName === e.target.value)
          ) {
            message.error('当前key重复了')
          }
          else {
            dispatch({
              type: 'modify_node_name',
              payload: {
                node: current,
                nodePath,
                newName: e.target.value,
              },
            })
          }
        }}
        className={styles.nodeName}
        disabled={isArrayItem}
        style={{
          width: width - offset,
        }}
      />

      {/* 值类型 */}
      <Select
        value={get(current, 'nodeType') || ANY_TYPE}
        placeholder="未知"
        onChange={(value) => {
          if (Tstate.previewMode)
            return

          changeNodeNormalAttr(value, `${prefix}nodeType`, 'nodeType', parent)
          // 因为array和object时，会自动最近一个默认子节点
          if ([OBJECT_TYPE, ARRAY_TYPE].includes(value)) {
            setLocalToggle({
              timestamp: +new Date(),
              status: true,
            })
          }
        }}
      >
        {SCHEMA_TYPE.map((item) => {
          return (
            <Option value={item} key={item}>
              {item}
            </Option>
          )
        })}
      </Select>

      {/* 标题 */}
      {/* <Input
        placeholder="标题"
        defaultValue={get(current, 'nodeTitle')}
        onBlur={e => changeNodeNormalAttr(e.target.value, `${prefix}nodeTitle`, 'nodeTitle')}
      /> */}

      {/* 操作 */}
      <Tooltip placement="top" title="高级设置">
        <Icon
          type="setting"
          className={classnames(styles.action, {
            [styles.setting]: hasRules(current),
          })}
          onClick={() => setSettingVisible(true)}
          // onClick={() => console.log(groupIndex, groupPrefix)}
        />
      </Tooltip>

      {!Tstate.previewMode && (
        <Tooltip placement="top" title="删除">
          {hasChildren(current)
            ? (
            <Popconfirm
              title="注意，所有子节点都会被删除！"
              onConfirm={() => deleteCurrentNode(nodePath)}
            >
              <Icon type="delete" className={classnames(styles.action, styles.delete)} />
            </Popconfirm>
              )
            : (
            <Icon
              type="delete"
              className={classnames(styles.action, styles.delete)}
              onClick={() => deleteCurrentNode(nodePath)}
            />
              )}
        </Tooltip>
      )}

      {!Tstate.previewMode && !disableAddNode && renderPlus(parent, current, nodePath)}

      {/* 只有数组，且当前分支下副本length >= 1时才能新增副本 */}

      {!Tstate.previewMode
        && get(current, 'nodeType') === ARRAY_TYPE
        && getCurrentGroups(current).length >= 1
        && !disableAddNode && (
          <Tooltip placement="top" title="新增副本">
            <Icon
              type="copy"
              className={classnames(styles.action, styles.copy)}
              onClick={() => {
                dispatch({ type: 'add_instance', payload: { current, nodePath } })
              }}
            />
          </Tooltip>
      )}

      {/* 只有数组才允许有多个副本，且当前分支下的副本个数 >= 1时才能有切换入口 */}
      {!Tstate.previewMode
        && get(current, 'nodeType') === ARRAY_TYPE
        && getCurrentGroups(current).length > 1 && (
          <Dropdown
            className="margin-right"
            placement="bottomRight"
            destroyOnClose
            overlay={
              <InstanceList
                current={current}
                groupName={getCurrentGroup(current).groupName}
                onSelect={groupIndex =>
                  dispatch({
                    type: 'switch_branch',
                    payload: { groupIndex, current, nodePath },
                  })
                }
                onRemove={group =>
                  dispatch({
                    type: 'delete_instance',
                    payload: { group, current, nodePath },
                  })
                }
              />
            }
          >
            <a
              className="ant-dropdown-link text-ellipsis inline-block"
              style={{ maxWidth: '100px', width: 'auto' }}
            >
              {getCurrentGroup(current).groupName || '切换'} <Icon type="down" />
            </a>
          </Dropdown>
      )}

      {!Tstate.previewMode && (
        <Tooltip placement="top" title="快速映射">
          <Badge dot={dotted}>
            <Icon
              type="share-alt"
              className={classnames(styles.action, styles.link)}
              style={{ marginRight: 4 }}
              onClick={handleSelect}
            />
          </Badge>
        </Tooltip>
      )}

      {Tstate.previewMode && <NodeInfo node={current} />}

      {show && children}
      {settingVisible && (
        <Drawer
          title={
            <>
              高级设置{' '}
              <Text code>
                {current.nodeName}({nodeName(current.nodeType)})
              </Text>
            </>
          }
          width={700}
          onClose={() => setSettingVisible(false)}
          visible={settingVisible}
          bodyStyle={{ paddingBottom: 80 }}
          destroyOnClose
        >
          {/* {mapping({ nodePath, parent, current, dispatch, close: setSettingVisible })} */}
          <ConfigPanel
            current={current}
            nodePath={nodePath}
            parent={parent}
            // group={getCurrentGroup(current) || {}}
            onClose={setSettingVisible}
          />
        </Drawer>
      )}
    </span>
  )
}

const NODE_TYPE = {
  nodeTitle: PropTypes.string,
  nodeName: PropTypes.string,
  nodeType: PropTypes.oneOf(SCHEMA_TYPE),
  children: PropTypes.array,
}

Node.propTypes = {
  parent: PropTypes.shape(NODE_TYPE),
  nodePath: PropTypes.string.isRequired,
  current: PropTypes.shape(NODE_TYPE).isRequired,
}

Node.defaultProps = {
  parent: undefined,
}

export default connect(({ setting }) => ({
  windowWidth: setting.size.width,
}))(Node)
